/*** 
 * @Author: pengcheng
 * @Date: 2021-06-24 10:27:50
 * @LastEditTime: 2021-08-24 14:10:39
 * @LastEditors: pengcheng
 * @Description: 
 * @FilePath: /kylin-daq/src/DataTransmit.cpp
 */
#include "TransmitModule.h"

QScopedPointer<TransmitModule> TransmitModule::ms_instance;
TransmitModule::TransmitModule(QObject *parent)
    : BaseModule(s_moduleName,parent)
    , m_mannager(new QNetworkAccessManager(this))
    , uploadTimer(new QTimer(this))
    , reuploadTimer(new QTimer(this))
{
    connect(this, &TransmitModule::uploadIntervalChanged, this, &TransmitModule::setUploadTimerPollingInterval);
    connect(this, &TransmitModule::reuploadIntervalChanged, this, &TransmitModule::setReuploadTimerPollingInterval);
    connect(uploadTimer, &QTimer::timeout, this , &TransmitModule::sendUploadInfoNum);
    connect(reuploadTimer, &QTimer::timeout, this , &TransmitModule::sendReuploadInfoNum);
}

TransmitModule::~TransmitModule()
{
}

TransmitModule::SendInfoStatus TransmitModule::sendInfo(const QList<QString> &info, const QString &urlValue, const QString &requestHead, const int32_t timeCountMsec)
{ 
    qDebug()<< "TransmitModule::sendInfo: urlValue="<<urlValue;
    QUrl url(urlValue);
    SendInfoStatus requestState=SendInfoStatus::OK;
    QString requestErrorRelyStr;
    int32_t requestErrorCode = 0;
    QJsonDocument requestHeadDoc = QJsonDocument::fromJson(requestHead.toUtf8());
    QJsonObject requestHeadObj =  requestHeadDoc.object();
    QByteArray requestData;
    //	检测url
    requestState = checkUrl(url);
    if(requestState == SendInfoStatus::OK)
    {
        // 检测待发送数据
        requestState = mergeInfo(info,requestData);
        if(requestState == SendInfoStatus::OK)
        {
            if(m_mannager->networkAccessible() == QNetworkAccessManager::NotAccessible)
            {
                m_mannager->setNetworkAccessible(QNetworkAccessManager::Accessible);
            }
            QNetworkRequest request;
            // 设置请求相关参数
            requestState = setRequest(request,url,requestHeadObj);
            if(requestState == SendInfoStatus::OK)
            {
                requestState = sendRequest(request,requestData,timeCountMsec,requestErrorCode,requestErrorRelyStr);
            }
        }
    }

    //  构造发送数据
    //  检查网络
    //  发送数据
    printSendInfoLog(info,requestState,requestErrorCode,requestErrorRelyStr);
    return requestState;
}

TransmitModule::SendInfoStatus TransmitModule::checkUrl(const QUrl &urlValue)
{
    //	检测url
    if(!urlValue.isValid())
    {
        return SendInfoStatus::FormatException;
    }
    if(urlValue.scheme() != "http"&&urlValue.scheme() != "https")
    {
        return SendInfoStatus::FormatException;
    }
    return SendInfoStatus::OK;

}

TransmitModule::SendInfoStatus TransmitModule::mergeInfo(const QList<QString> &info, QByteArray &requestData)
{
    QJsonArray mergeJsonObject;
    QJsonObject sendedJsonObject;
    foreach(const QString &tempInfo, info)
    {
        QJsonDocument tempJsonDoc = QJsonDocument::fromJson(tempInfo.toUtf8());
        if(!tempJsonDoc.isObject())
        {
            continue;
        }
        QJsonObject tempJsonObj =  tempJsonDoc.object();
        if(!tempJsonObj.contains(gs_sourceKey)
            || !tempJsonObj.contains(gs_informationKey)
            || !tempJsonObj[gs_sourceKey].isObject()
            || !tempJsonObj[gs_informationKey].isObject())
        {
            continue;
        }
        QJsonObject sourceJsonObj(tempJsonObj[gs_sourceKey].toObject());
        QJsonObject informationJsonObj(tempJsonObj[gs_informationKey].toObject());
        // 去除information中不符合条件的数据
        if(informationJsonObj.contains(gs_packageNameKey)
                || informationJsonObj.contains(gs_messageTypeKey)
                || informationJsonObj.contains(gs_tidKey)
                || informationJsonObj.contains(gs_parentTidKey))
        {
           continue;
        }
        QJsonObject  waitAddJsonObj(informationJsonObj);
        if(!sourceJsonObj.contains(gs_packageNameKey)
                || !sourceJsonObj.contains(gs_messageTypeKey)
                || !sourceJsonObj.contains(gs_tidKey))
        {
            continue;
        }
        waitAddJsonObj.insert(gs_packageNameKey,sourceJsonObj[gs_packageNameKey].toString());
        waitAddJsonObj.insert(gs_messageTypeKey,sourceJsonObj[gs_messageTypeKey].toString());
        waitAddJsonObj.insert(gs_tidKey,sourceJsonObj[gs_tidKey].toString());
        if(sourceJsonObj.contains(gs_parentTidKey))
        {
            waitAddJsonObj.insert(gs_parentTidKey,sourceJsonObj[gs_parentTidKey].toString());
        }
        if(waitAddJsonObj.contains(s_uploadTimeKey)) {
            waitAddJsonObj[s_uploadIntervalKey]=QDateTime::currentDateTime().toTimeZone(QTimeZone(gs_timezone)).toString(gs_timeFormat);
        }
        else
        {
            waitAddJsonObj.insert(s_uploadTimeKey,QDateTime::currentDateTime().toTimeZone(QTimeZone(gs_timezone)).toString(gs_timeFormat));
        }
        mergeJsonObject.append(QString(QJsonDocument(waitAddJsonObj).toJson(QJsonDocument::Compact)));
    }
    if(mergeJsonObject.isEmpty())
    {
        return SendInfoStatus::FormatException;
    }
    sendedJsonObject.insert(s_messageKey,mergeJsonObject);
    requestData = QJsonDocument(sendedJsonObject).toJson(QJsonDocument::Compact);
    return SendInfoStatus::OK;

}

TransmitModule::SendInfoStatus TransmitModule::setRequest(QNetworkRequest &request, const QUrl &url, const QJsonObject &requestHeadObj)
{
    if(url.scheme() == "https")
    {
        QSslConfiguration config;
        config.setProtocol(QSsl::TlsV1SslV3);
        config.setPeerVerifyMode(QSslSocket::PeerVerifyMode::VerifyNone);
        request.setSslConfiguration(config);
    }
    //	设置请求
    for(auto iter = requestHeadObj.begin();iter != requestHeadObj.end();iter++)
    {
        if(iter.value().isString())
        {
            qDebug()<<iter.value().isString();
            request.setRawHeader(iter.key().toUtf8(),iter.value().toString().toUtf8());
        }
    }
    request.setRawHeader(s_httpUploadTimeStamp,QDateTime::currentDateTime().toTimeZone(QTimeZone(gs_timezone)).toString(gs_timeFormat).toUtf8());
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(s_requestTyepValue));
    request.setUrl(url);
    return SendInfoStatus::OK;
}

TransmitModule::SendInfoStatus TransmitModule::sendRequest(QNetworkRequest &request, const QByteArray &requestData, const int32_t timeCountMsec, int32_t &requestErrorCode, QString &requestErrorRelyStr)
{
    QTimer timer;
    QEventLoop eventLoop;
    SendInfoStatus requestState = SendInfoStatus::OK;
    QNetworkReply *tempReply = m_mannager->post(request, requestData);
    connect(tempReply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);
    timer.setSingleShot(true);
    timer.start(timeCountMsec);
    eventLoop.exec();
    if (!timer.isActive()) {
        qDebug() << "post响应超时";
        tempReply->abort();
    }
    if (tempReply->error() == QNetworkReply::NoError) {
        QVariant stateCode = tempReply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
        if (stateCode.isValid()) {
            if (stateCode.toInt() == s_httpReplyValidCode) {
                requestState = SendInfoStatus::OK;
                QJsonDocument replyDoc = QJsonDocument::fromJson(tempReply->readAll());
                if(replyDoc.isObject())
                {
                    QJsonObject replyObj = replyDoc.object();
                    if (replyObj.contains(s_replyErrorCodeKey))
                    {
                        if (replyObj[s_replyErrorCodeKey].toInt() != s_replyValidCode)
                        {
                            requestState = SendInfoStatus::ServerReplyException;
                            requestErrorCode = replyObj[s_replyErrorCodeKey].toInt();
                            if (replyObj.contains(s_replyErrorMsgKey))
                            {
                                requestErrorRelyStr = replyObj[s_replyErrorMsgKey].toString();
                            }
                        }
                    }
                }
            } else {
                requestState = SendInfoStatus::ServerException;
                requestErrorCode = stateCode.toInt();
            }
        } else {
            requestState = SendInfoStatus::ServerException;
        }
    } else {
        requestState = SendInfoStatus::NetworkAnomaly;
        requestErrorCode = tempReply->error();
    }
    tempReply->deleteLater();
    return requestState;
}

void TransmitModule::printSendInfoLog(const QList<QString> &info, const TransmitModule::SendInfoStatus &requestState, int32_t requestErrorCode, const QString &requestErrorRelyStr)
{
    switch (requestState)
    {
    case SendInfoStatus::OK:
        qInfo().noquote() << QString("TransmitModule::sendInfo: requestInfoNum = %1,requestState=%2").arg(info.size()).arg(QString::number(requestState));
        break;
    case SendInfoStatus::FormatException:
        qInfo().noquote() << QString("TransmitModule::sendInfo: requestInfoNum = %1,requestState=%2").arg(info.size()).arg(QString::number(requestState));
        break;
    case SendInfoStatus::NetworkAnomaly:
        qInfo().noquote() << QString("TransmitModule::sendInfo: requestInfoNum = %1,requestState=%2, ErrorCode=%3").arg(info.size()).arg(QString::number(requestState),QString::number(requestErrorCode));
        break;
    case SendInfoStatus::ServerException:
        qInfo().noquote() << QString("TransmitModule::sendInfo: requestInfoNum = %1,requestState=%2, ErrorCode=%3").arg(info.size()).arg(QString::number(requestState),QString::number(requestErrorCode) );
        break;
    case SendInfoStatus::ServerReplyException:
        qInfo().noquote() << QString("TransmitModule::sendInfo: requestInfoNum = %1,requestState=%2, ErrorCode=%3, RelyStr=%4").arg(info.size()).arg(QString::number(requestState),QString::number(requestErrorCode) ,requestErrorRelyStr);
        break;
    case SendInfoStatus::UrlException:
        qInfo().noquote() << QString("TransmitModule::sendInfo: requestInfoNum = %1,requestState=%2").arg(info.size()).arg(QString::number(requestState));
        break;
    default:
        break;
    }
}

void TransmitModule::sendUploadInfoNum()
{
    if(uploadState() == UploadEnable)
    {
       emit uploadInfoSignal(m_numOfUploadedLines);
    }
}

void TransmitModule::sendReuploadInfoNum()
{
    if(uploadState() == UploadEnable)
    {
       emit reuploadInfoSignal(m_numOfReuploadedLines);
    }
}

void TransmitModule::uploadInfo(const QList<qlonglong> &id,const QList<QString> &info,const QList<QString> & status, const QString &requestHead)
{
    if(info.size()>0 && networkIsConnected())
    {

        SendInfoStatus sendInfoStatus = sendInfo(info,m_uploadRealm + s_uploadUrl,requestHead,s_timerCountMsec);
        qInfo()<< "TransmitModule::uploadInfo";
        emit retUploadState(id,info,status, sendInfoStatus);
    }
}

void TransmitModule::reuploadInfo(const QList<qlonglong> &id,const QList<QString> &info,const QList<QString> & status, const QString &requestHead)
{
    if(info.size()>0 && networkIsConnected())
    {
        SendInfoStatus sendInfoStatus = sendInfo(info,m_uploadRealm + s_reuploadUrl,requestHead,s_timerCountMsec);
        qInfo()<< "TransmitModule::reuploadInfo";
        emit retReuploadState(id,info,status, sendInfoStatus);

    }
}

void TransmitModule::setUploadTimerPollingInterval(qlonglong sec)
{
    uploadTimer->stop();
    uploadTimer->setInterval(secToMsec(sec));
    uploadTimer->start();
}

void TransmitModule::setReuploadTimerPollingInterval(qlonglong sec)
{
    reuploadTimer->stop();
    reuploadTimer->setInterval(secToMsec(sec));
    reuploadTimer->start();
}

void TransmitModule::printConf()
{
    qDebug()<<"uploadInterval:"<<m_uploadInterval;
    qDebug()<<"reuploadInterval:"<<m_reuploadInterval;
    qDebug()<<"numOfUploadedLines:"<<m_numOfUploadedLines;
    qDebug()<<"numOfReuploadedLines:"<<m_numOfReuploadedLines;
//    qDebug()<<"uploadState:"<<m_uploadState;
}

void TransmitModule::updateProperty(const QJsonObject &conf, const QJsonObject &defaultConf)
{
    if(defaultConf.contains(moduleName())
       && defaultConf[moduleName()].isObject()
      )
    {
        QJsonObject moduleConf;
        QJsonObject moduleDefaultConf = defaultConf[moduleName()].toObject();
        qlonglong value;
        if(conf.contains(moduleName())
          && conf[moduleName()].isObject())
        {
            moduleConf = conf[moduleName()].toObject();
        }
        //	设置上传间隔
        if(getValidConfInt(moduleConf,moduleDefaultConf,s_uploadIntervalKey,value) == FunctionSeccess)
        {
            setUploadInterval(value);
            qInfo()<<"module="<<moduleName()<<",property="<<s_uploadIntervalKey<<":"<<value;
        }
        else
        {
            qCritical()<<"module="<<moduleName()<<",property="<<s_uploadIntervalKey<<":read conf fail";
        }
        //	设置重传间隔
        if(getValidConfInt(moduleConf,moduleDefaultConf,s_reuploadIntervalKey,value) == FunctionSeccess)
        {
            setReuploadInterval(value);
            qInfo()<<"module="<<moduleName()<<",property="<<s_reuploadIntervalKey<<":"<<value;
        }
        else
        {
            qCritical()<<"module="<<moduleName()<<",property="<<s_reuploadIntervalKey<<":read conf fail";
        }
        //  设置上传条数
        if(getValidConfInt(moduleConf,moduleDefaultConf,s_numOfUploadedLinesKey,value) == FunctionSeccess)
        {
            setNumOfUploadedLines(value);
            qInfo()<<"module="<<moduleName()<<",property="<<s_numOfUploadedLinesKey<<":"<<value;
        }
        else
        {
            qCritical()<<"module="<<moduleName()<<",property="<<s_numOfUploadedLinesKey<<":read conf fail";
        }
        //  设置重传条数
        if(getValidConfInt(moduleConf,moduleDefaultConf,s_numOfReuploadedLinesKey,value) == FunctionSeccess)
        {
            setNumOfReuploadedLines(value);
            qInfo()<<"module="<<moduleName()<<",property="<<s_numOfReuploadedLinesKey<<":"<<value;
        }
        else
        {
            qCritical()<<"module="<<moduleName()<<",property="<<s_numOfReuploadedLinesKey<<":read conf fail";
        }
        //  设置上传状态
        if(getValidConfInt(moduleConf,moduleDefaultConf,s_uploadStateKey,value) == FunctionSeccess)
        {
            setUploadState(UploadState(value));
            qInfo()<<"module="<<moduleName()<<",property="<<s_uploadStateKey<<":"<<value;
        }
        else
        {
            qCritical()<<"module="<<moduleName()<<",property="<<s_uploadStateKey<<":read conf fail";
        }
        //  设置域
        if(moduleDefaultConf.contains(s_uploadRealm)
                && moduleDefaultConf[s_uploadRealm].isObject()
                && moduleDefaultConf[s_uploadRealm].toObject().contains(gs_defaultStr))
        {
            if(moduleConf.contains(s_uploadRealm)
                && moduleConf[s_uploadRealm].isString())
            {
                setUploadRealm(moduleConf[s_uploadRealm].toString());
                qInfo()<<"module="<<moduleName()<<",property="<<s_uploadRealm<<":"<<moduleConf[s_uploadRealm].toString();
            }
            else
            {
                setUploadRealm(moduleDefaultConf[s_uploadRealm].toString());
                qInfo()<<"module="<<moduleName()<<",property="<<s_uploadRealm<<":"<<moduleDefaultConf[s_uploadRealm].toString();
            }
        }
        else
        {
            qCritical()<<"module="<<moduleName()<<",property="<<s_uploadRealm<<":read conf fail";
        }
    }
    else
    {
            qCritical()<<"module="<<moduleName()<<":update property fail";
    }
}

TransmitModule *TransmitModule::instance()
{
    if (ms_instance.isNull()) {
        ms_instance.reset(new TransmitModule());
    }
    return ms_instance.data();

}

/*判断网络是否连接*/
bool TransmitModule::networkIsConnected()
{
    QDBusInterface *networkService =  new QDBusInterface("org.freedesktop.NetworkManager",
                                                         "/org/freedesktop/NetworkManager",
                                                         "org.freedesktop.NetworkManager",
                                                         QDBusConnection::systemBus());
    if(!networkService->isValid())
    {
        qWarning() << "网络Service Interface: " << qPrintable(QDBusConnection::systemBus().lastError().message());
        return false;
    }
    QDBusMessage message = networkService->call(QDBus::Block, "state");
    if (message.type() == QDBusMessage::ReplyMessage)
    {
        //从返回参数获取返回值
        uint32_t value = message.arguments().takeFirst().toUInt();
        if (value == 70)
        {
            return true;
        }
        else
        {
            qWarning() << "网络状态接口返回值：" << value;
            return false;
        }
    }
    qWarning() << "获取网络状态接口返回值失败";
    return false;
}
